public abstract class Robot
{
	protected final static int UNKNOWN = 0;
	protected final static int VIRWALL = 1;
	protected final static int VISITED_D0 = 2;
	protected final static int VISITED_D1 = 4;
	protected final static int VISITED_D2 = 8;
	protected final static int VISITED_D3 = 16;
	
	protected Labyrinthe laby;
	protected int preferences[];
	protected int vgrid[][];
	protected MyPosition cur;

	public Robot(Labyrinthe lab, int[] prefs)
	{
		laby = lab;
		preferences = prefs;
		vgrid = new int[2*lab.getRows()+1][2*lab.getCols()+1];
		cur = new MyPosition(0, 0);
	}
	
	private MyPosition applyDirection(MyPosition p, int dir)
	{
		switch (dir)
		{
			case Labyrinthe.UP: return new MyPosition(p.x, p.y-1);
			case Labyrinthe.RIGHT: return new MyPosition(p.x+1, p.y);
			case Labyrinthe.DOWN: return new MyPosition(p.x, p.y+1);
			case Labyrinthe.LEFT: return new MyPosition(p.x-1, p.y);
			default: return null;
		}
	}
	
	protected int dirToVisited(int dir)
	{
		if (preferences[0] == dir) return VISITED_D0;
		else if (preferences[1] == dir) return VISITED_D1;
		else if (preferences[2] == dir) return VISITED_D2;
		else if (preferences[3] == dir) return VISITED_D3;
		else throw new IllegalArgumentException();
	}
	
	private int getCell(MyPosition p)
	{
		return vgrid[p.y+laby.getRows()][p.x+laby.getCols()];
	}
	
	private void setCell(MyPosition p, int v)
	{
		vgrid[p.y+laby.getRows()][p.x+laby.getCols()] = v;
	}
	
	protected boolean canVisit(int dir, int curFlag)
	{
		if (laby.isWall(dir)) return false;
		int val = getCell(applyDirection(cur, dir));
		return (val&VIRWALL)==0 && (val&curFlag)==0;
	}
	
	protected boolean canVisit(int dir)
	{
		return canVisit(dir, VISITED_D0|VISITED_D1|VISITED_D2|VISITED_D3);
	}
	
	protected boolean isWall(int dir)
	{
		return laby.isWall(dir) || getCell(applyDirection(cur, dir))==VIRWALL;
	}
	
	protected void resetVisited()
	{
		setCell(cur, UNKNOWN);
	}
	
	protected void setWall()
	{
		setCell(cur, VIRWALL);
	}
	
	protected boolean move(int dir)
	{
		if (isWall(dir)) return false;
		setCell(cur, getCell(cur) | dirToVisited(dir));
		laby.go(dir); //it WILL work (checked before)
		cur = applyDirection(cur, dir);
		return true;
	}


	public abstract int findExit();
}

